<template>
  <div class="container">
    <button class="gen-btn" @click="generate">获取数据</button>
    <div class="list-view" @scroll="handleScroll">
      <ul class="list" :style="listStyle">
        <li
          class="list-item"
          v-for="(val, index) in renderList"
          :key="index"
          :style="itemStyle"
        >
          {{ val }}
        </li>
      </ul>
    </div>
  </div>
</template>


<script>
// 可视区元素的数量
const viewLength = 6
// 缓冲区元素数量
const bufferLength = 2
// 元素高度
const itemHeight = 100
export default {
  name: 'VirtualList',
  components: {},
  props: [],
  data() {
    return {
      list: [],
      renderList: [],
      listStyle: {
        height: '100px',
        padding: '0px'
      },
      itemStyle: {
        transform: `translateY(0px)`
      }
    };
  },
  methods: {
    generate() {
      const arr = []
      for (let i = 0; i < 10000; i++) {
        arr.push(i.toLocaleString())
      }
      this.list = arr
      // 扩充列表宽度
      this.listStyle.height = `${this.list.length * itemHeight}px`
      // 排布可见区和缓冲区数据
      this.renderList = this.list.slice(0, viewLength + bufferLength)
    },
    handleScroll(e) {
      // 当前滚动高度
      const scrollTop = e.target.scrollTop
      // 根据当前滚动高度计算元素偏移量
      const itemOffset = Math.floor(scrollTop / itemHeight)
      // 根据元素偏移量计算元素的高度偏移量
      const offsetY = itemOffset * itemHeight
      this.itemStyle.transform = `translateY(${offsetY}px)`

      this.renderList = this.list.slice(itemOffset, itemOffset + viewLength + bufferLength)
    }
  },
  created() {},
  mounted() {}
};
</script>

<style lang="less" scoped>
.container {
  width: 400px;
  margin: 0 auto;
  .gen-btn {
    width: 100px;
    height: 30px;
    margin-bottom: 10px;
  }
}
.list-view {
  width: 400px;
  height: 600px;
  margin: 0 auto;
  overflow-y: scroll;
  border: 1px solid #aaa;
  .list {
    .list-item {
      height: 100px;
      text-align: center;
      line-height: 100px;
      color: red;
      border-bottom: 1px solid #eee;
    }
  }
}
</style>